use futures_util::future;
use ratatui::widgets::Row;
use tokio::time;

use crate::{config::SDConfig, tui::ui::TableData};

/// Application result type.
pub type AppResult<T> = anyhow::Result<T>;

pub(crate) enum NavDirection {
    Up(u32),
    Down(u32),
    Left(u32),
    Right(u32),
}

/// Application.
#[derive(Debug)]
pub struct App {
    /// Is the application running?
    pub running: bool,
    pub sd_cfg: SDConfig,
    pub current_tab: usize,
    pub current_row: isize,
    pub current_col: usize,
    pub downloading_row: Option<usize>,
    pub downloading_progress: f64,
    pub downloading_future: Option<Pin<Box>>,
}

impl App {
    /// Constructs a new instance of [`App`].
    pub fn new(cfg: SDConfig) -> Self {
        Self {
            running: true,
            sd_cfg: cfg,
            current_tab: 0,
            current_row: 0,
            current_col: 0,
            downloading_row: None,
            downloading_progress: 0.0,
            downloading_future: None,
        }
    }

    /// Handles the tick event of the terminal.
    pub fn tick(&self) {}

    /// Set running to false to quit the application.
    pub async fn quit(&mut self) {
        self.running = false;
    }

    pub fn get_rows(&mut self) -> Vec<Row> {
        self.sd_cfg.to_table_data()
    }
    pub async fn switch_tab(&mut self, tab: usize) {
        self.current_tab = tab;
        self.current_row = 0;
    }
    pub async fn goto(&mut self, dir: NavDirection) {
        match dir {
            NavDirection::Up(n) => {
                self.current_row = self.current_row.saturating_sub(n as isize);
                if self.current_row < 0 {
                    self.current_row = (self.get_rows().len() - 1) as isize;
                }
            }
            NavDirection::Down(n) => {
                self.current_row = self.current_row.saturating_add(n as isize);
                if self.current_row >= self.get_rows().len() as isize {
                    self.current_row = 0;
                }
            }
            NavDirection::Left(n) => {
                self.current_col = self.current_col.saturating_sub(n as usize);
            }
            NavDirection::Right(n) => {
                self.current_col = self.current_col.saturating_add(n as usize);
            }
        }
    }
    pub async fn mark_download(&mut self) {
        self.downloading_row = Some(self.current_row.clone() as usize);
        let future = self.download();
        let f = Some(Box::pin(future));
    }
    pub async fn download(&mut self) -> AppResult<()> {
        log::info!(
            "downloading row {:?}",
            self.sd_cfg.data()[self.current_row as usize]
        );
        loop {
            time::sleep(time::Duration::from_millis(100)).await;
            self.downloading_progress += 0.05;
            if self.downloading_progress >= 1.0 {
                self.downloading_row = None;
                self.downloading_progress = 0.0;
                return Ok(());
            }
        }
    }
}
